package umg;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Random;
import java.util.StringTokenizer;
import java.util.Vector;

import javax.swing.ImageIcon;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;

import umg.gui.GUI;
import umg.gui.RollOverJTable;
import umg.util.CountryLookup;
import umg.util.DBUtil;
import umg.util.HTMLStreamUtils;
import umg.util.PropertyManager;
import umg.vo.MatchSnapShotVO;
import umg.vo.PlayerVO;
import umg.vo.TwoStrings;

public class PlayerReaderThread extends Thread
{
	private int server = 0;
	static DBUtil db = null;
	MatchSnapShotVO match = null;
	static Integer runCount = 1;// static makes it common to all threads.
	static HashMap<String, String> warnedPlayerIPHashMap;
	private static final Object syncObject = new Object();
	static long lastSaveTime = 0;
	long lastAdTime = 0, lastAd2Time = 0;//one for each server.
	boolean ad2shown = true;
	boolean countryShown = false;
	long lastTimeCountryShown = 0;
	Boolean isGrabInProgress = Boolean.FALSE;
	String serverName = null;
	static HashMap<String, String> kickNamesMap = null;// shared among all threads.
	CountryLookup countryLookup = new CountryLookup();
	static HashMap<String, ImageIcon> flagIconHashMap;
	HashMap<String, String> countryHashMap;
	TableModel tableModel = null;
	RollOverJTable tableToPopulate = null;
	Object data[][] = null;

	public PlayerReaderThread(final int server_index)
	{
		super();
		this.server = server_index;

		if (db == null)
		{
			db = new DBUtil();
		}
		countryHashMap = new HashMap<String, String>(Constants.MAXPLAYERS);
		tableToPopulate = GUI.matchSnapShotTables[server];
		//threadStartTime=System.currentTimeMillis();

	}

	int tempPriority = 0;

	@Override
	public void run()
	{
		this.setPriority(PropertyManager.getThreadPriorityInt());
		this.setName(PropertyManager.getWebadminURLNames()[server] + Messages.getString("PlayerReaderThread.0"));
		if (PropertyManager.isDebug()) System.out.println(Messages.getString("PlayerReaderThread.1") + this.getName() + Messages.getString("PlayerReaderThread.2") + Constants.SPACE_STR + this.getPriority());

		try
		{
			Random randomGenerator = new Random();
			int startupSleepms = randomGenerator.nextInt(5 * 1000);
			// System.out.println("\""+this.getName()+"\" is starting after a random wait of "+startupSleepms+"ms with priority of "+this.getPriority());
			// GUI.logToStatus("\""+this.getName()+"\" is starting after a random wait of "+startupSleepms+"ms with priority of "+this.getPriority());
			sleep(startupSleepms);
		}
		catch (InterruptedException e1)
		{
			e1.printStackTrace();
		}
		long tempTime = 0;

		while (true)
		{
			if (tempPriority != PropertyManager.getThreadPriorityInt())
			{
				this.setPriority(PropertyManager.getThreadPriorityInt());
				tempPriority = PropertyManager.getThreadPriorityInt();
				GUI.logToStatus(Messages.getString("PlayerReaderThread.3") + this.getName() + Messages.getString("PlayerReaderThread.4") + Constants.SPACE_STR + this.getPriority());
			}
			//only try to save/gc if we are actively updating the database.
			if (GUI.databaseQueryModeMenuItem != null && GUI.databaseQueryModeMenuItem.isSelected() == false)
			{
				try
				{
					tempTime = System.currentTimeMillis();
					getDataRefreshTablesAndSave(tempTime);
					//spit out the ad if we have crossed the AD_INTERVAL;
					synchronized (syncObject)//sync because it affects all threads
					{
						if (lastAdTime == 0) lastAdTime = tempTime;

						if (tempTime > (lastAdTime + Constants.AD_START_DELAY_INTERVAL) && PropertyManager.getShowAd().equalsIgnoreCase("true") && ad2shown == false)//delay 3 seconds
						{
							HTMLStreamUtils.sendText(server, Constants.AD_MESSAGE2);
							ad2shown = true;//ok to show ad2 once.
							if (PropertyManager.isDebug()) System.out.println(new java.util.Date() + " - Showed Ad2 for server:" + server);
						}

						if ((tempTime - lastAdTime) > Constants.AD_INTERVAL && PropertyManager.getShowAd().equalsIgnoreCase("true"))
						{
							HTMLStreamUtils.sendText(server, Constants.AD_MESSAGE1a);
							HTMLStreamUtils.sendText(server, Constants.AD_MESSAGE1b);
							lastAdTime = tempTime;
							ad2shown = false;
							if (PropertyManager.isDebug()) System.out.println(new java.util.Date() + " - Showed Ad1 for server:" + server);
						}
					}

					synchronized (syncObject)//sync because it affects all threads
					{
						if (lastTimeCountryShown == 0) lastTimeCountryShown = tempTime;
						if ((tempTime - lastTimeCountryShown) > Constants.SHOW_COUNTRIES_INTERVAL && PropertyManager.getShowCountries().equalsIgnoreCase("true"))
						{
							int size = countryHashMap.size();
							if (size > 1)//dont show if theres only one country
							{
								StringBuffer countryText = new StringBuffer();
								Vector<String> v = new Vector<String>(countryHashMap.keySet());
								//System.out.println("Countries: "+countryHashMap.keySet());
								Collections.sort(v);
								Iterator<String> iter = v.iterator();
								String key = null;
								while (iter.hasNext())
								{
									key = iter.next();
									if (countryHashMap.get(key).equalsIgnoreCase(CountryLookup.UNK)) continue;
									if (countryText.length() > 0) countryText.append(",");
									countryText.append(countryHashMap.get(key));
								}
								HTMLStreamUtils.sendText(server, Constants.COUNTRY_MSG + countryText.toString());
								if (PropertyManager.isDebug()) System.out.println(new java.util.Date() + " Server:" + server + " " + Constants.COUNTRY_MSG + countryText.toString());
							}
							lastTimeCountryShown = tempTime;
						}//show countries
					}


					if (runCount % Constants.GARBAGE_COLLECT_EVERY_RUNS == 0)
					{
						System.gc();
					}
					runCount++;

					//delay
					sleep(Integer.parseInt(PropertyManager.getGrab_interval()) * 1000);

				}// try
				catch (InterruptedException e)
				{
				}
				catch (Exception e)
				{
					System.out.println(Messages.getString("PlayerReaderThread.5") + e.getMessage() + Messages.getString("PlayerReaderThread.6") + server + Messages.getString("PlayerReaderThread.7"));
					e.printStackTrace();
				}
			}

		}// while
	}

	public void getDataRefreshTablesAndSave(final long scheduledExecutionTime)
	{
		long startTime = System.currentTimeMillis();
		synchronized (syncObject)
		{
			if (isGrabInProgress == false)
			{
				isGrabInProgress = Boolean.TRUE;
				if (PropertyManager.isDebug()) System.out.println(Messages.getString("PlayerReaderThread.8") + server);
			}
			else
			{
				// System.out.println(
				// "Skipping getDataRefreshTablesAndSave for url #"+url_number);
				return;
			}
		}
		try
		{
			if (db == null) db = new DBUtil();
			// db.fixAliasIssue();
			// FOR loop to go through all url_numbers 1..n
			if (PropertyManager.getWebadminURLs().length == 0)
			{
				GUI.logToStatus(Messages.getString("PlayerReaderThread.9"));
				return;
			}
			if (serverName == null) serverName = PropertyManager.getWebadminURLNames()[server];

			if (warnedPlayerIPHashMap == null)
			{
				warnedPlayerIPHashMap = new HashMap<String, String>();
			}

			DateFormat dateFormat = new SimpleDateFormat(Messages.getString("PlayerReaderThread.10"));

			if (System.currentTimeMillis() - scheduledExecutionTime >= (Constants.MAX_TARDINESS * (server + 1)))
			{
				if (PropertyManager.isDebug()) System.out.println(Messages.getString("PlayerReaderThread.11") + server);
				return; // Too late, skip this execution.
			}
			// get match info
			match = HTMLStreamUtils.getMatchSnapShot(server, scheduledExecutionTime);
			if (PropertyManager.isDebug()) System.out.println(Messages.getString("PlayerReaderThread.12") + server);
			if (match == null || (match != null && match.getPlayers().length == 0))
			{
				if (PropertyManager.isDebug()) System.out.println(Messages.getString("PlayerReaderThread.13") + server);
				return;
			}
			else
			{
				if (PropertyManager.isDebug()) System.out.println(Messages.getString("PlayerReaderThread.14") + match.getPlayers().length + Messages.getString("PlayerReaderThread.15") + server);
				GUI.lastMatchData[server]=match;
			}

			db.saveMatchSnapShot(match, server);

			GUI.setLastRefreshTextField(dateFormat.format(match.getTimestamp()));

			PlayerVO players[] = match.getPlayers();
			TwoStrings country = null;

			// update the JTable, iff the gui setting "dontUpdateScreen" is false
			if (GUI.getDontUpdateValue() == false && GUI.isWindowShowing() == true)
			{
				data = new Object[players.length][Constants.TABLE_HEADER.length];
				ImageIcon icon = null;
				for (int row = 0; row < players.length; row++)
				{
					country = countryLookup.locate(players[row].getIP());//takes care of not found too.
					if (flagIconHashMap == null) flagIconHashMap = new HashMap<String, ImageIcon>(300);
					//try to get the icon from the hashmap
					icon = flagIconHashMap.get(country.getValue2());
					if (icon == null)
					{
						icon = new ImageIcon(country.getValue1(), country.getValue2());
						//add it to the hashmap for next time
						if (icon != null)
						{
							flagIconHashMap.put(country.getValue2(), icon);
							if (PropertyManager.isDebug()) System.out.println("Added flag icon to cache:" + country.getValue2());
						}
					}
					data[row][0] = players[row].getPlayerName();
					data[row][1] = icon;
					data[row][2] = players[row].getPing();
					data[row][3] = players[row].getScore();
					data[row][4] = players[row].getIP();
					data[row][5] = players[row].getTeam();
					data[row][6] = players[row].getWebID();
				}
				tableModel = new DefaultTableModel(data, Constants.TABLE_HEADER);
				// select based on the url_number passed in (1=tab1, 2=tab2...)
				tableToPopulate.setModel(tableModel);
				GUI.setColumnWidthsForJTable(tableToPopulate);

				GUI.playerData[server] = data;//data.clone();
				//GUI.redraw();
			}

			//things to do regardless of whether we are updating the UI
			countryHashMap.clear();
			for (int row = 0; row < players.length; row++)
			{
				//manage country hashmap, for the country message.
				country = countryLookup.locate(players[row].getIP());
				if (country != null && country.getValue1() != null && country.getValue1().length() > 0)
				{
					//country found
					if (countryHashMap.get(country.getValue1()) == null)
					{//not found, add
						countryHashMap.put(country.getValue1(), country.getValue2());
					}

					//auto kick if this person is using a proxy
					if (country.getValue2().toLowerCase().indexOf("proxy") != -1 && PropertyManager.getAutokickProxyUsersEnabled().equalsIgnoreCase("true"))
					{
						HTMLStreamUtils.kickID(server, players[row].getWebID());
						GUI.logToStatus(serverName + Messages.getString("GUI.160") + Messages.getString("PlayerReaderThread.16") + players[row].getPlayerName() + Messages.getString("PlayerReaderThread.17") + players[row].getIP() + Messages.getString("PlayerReaderThread.17") + players[row].getTeam() + Messages.getString("PlayerReaderThread.36") + "(proxy:" + country.getValue2() + ")"); //$NON-NLS-4$
					}
				}

				// auto kick if the name is in the auto kick list.
				if (PropertyManager.getAutoKickPlayerList().length() > 0 && players[row].getPlayerName() != null && isNameInAutoKickList(players[row].getPlayerName()))
				{
					HTMLStreamUtils.kickID(server, players[row].getWebID());
					GUI.logToStatus(serverName + Messages.getString("GUI.160") + Messages.getString("PlayerReaderThread.16") + players[row].getPlayerName() + Messages.getString("PlayerReaderThread.17") + players[row].getIP() + Messages.getString("PlayerReaderThread.17") + players[row].getTeam() + Messages.getString("PlayerReaderThread.36")); //$NON-NLS-4$
				}

				// autoKick "Player".
				if (PropertyManager.getAutokickPlayerEnabled().equalsIgnoreCase(Messages.getString("PlayerReaderThread.37")) && players[row].getPlayerName() != null && players[row].getPlayerName().equalsIgnoreCase(Messages.getString("PlayerReaderThread.21")))
				{
					// do we have a warn list? if yes go thru it and add at
					// the end if the players ip was not found.
					String warnedIP = warnedPlayerIPHashMap.get(players[row].getIP());
					if (players[row].getIP() != null && warnedIP != null && warnedIP.equalsIgnoreCase(players[row].getIP()))
					{
						// found this ip had a warning
						HTMLStreamUtils.sendText(server, Messages.getString("PlayerReaderThread.22"));
						HTMLStreamUtils.kickID(server, players[row].getWebID());
						GUI.logToStatus(serverName + Messages.getString("GUI.160") + Messages.getString("PlayerReaderThread.16") + players[row].getPlayerName() + Messages.getString("PlayerReaderThread.17") + players[row].getIP() + Messages.getString("PlayerReaderThread.17") + players[row].getTeam() + Messages.getString("PlayerReaderThread.43")); //$NON-NLS-4$
						// warnedPlayerIPHashMap.remove(players[row].getIP());
					}
					else
					{
						if (players[row].getIP() != null)
						{
							HTMLStreamUtils.sendText(server, PropertyManager.getAutoKickMessage() + Messages.getString("PlayerReaderThread.44") + Constants.SPACE_STR + PropertyManager.getGrab_interval() + Messages.getString("PlayerReaderThread.45"));
							GUI.logToStatus(serverName + Messages.getString("GUI.160") + Messages.getString("PlayerReaderThread.16") + players[row].getPlayerName() + Messages.getString("PlayerReaderThread.17") + players[row].getIP() + Messages.getString("PlayerReaderThread.17") + players[row].getTeam() + Messages.getString("PlayerReaderThread.49")); //$NON-NLS-4$
							// at the last element, and not found
							warnedPlayerIPHashMap.put(players[row].getIP(), players[row].getIP());
						}
					}
				} //autoKick "Player".
			}//for loop thru players

			if (PropertyManager.isDebug())
			{
				long endTime = System.currentTimeMillis();
				System.out.println(Messages.getString("PlayerReaderThread.50") + server + Messages.getString("PlayerReaderThread.51") + (endTime - startTime) + Messages.getString("PlayerReaderThread.52"));
			}
		}
		catch (Exception e)
		{
			e.printStackTrace();
		}
		finally
		{
			isGrabInProgress = Boolean.FALSE;
		}
	}

	/**
	 * if this players name has a a banned word, kick.
	 * case insensitive
	 * @param name
	 * @return
	 */
	private boolean isNameInAutoKickList(String name)
	{
		//get the array of names from PropertyManager and see if this name should be kicked
		//changed to allow substring matches
		String autoKickPlayerList = PropertyManager.getAutoKickPlayerList();
		StringTokenizer st = new StringTokenizer(autoKickPlayerList, Constants.NAME_LIST_SEPERATOR);
		while (st.hasMoreTokens())
		{
			if (name.toLowerCase().indexOf(st.nextToken().toLowerCase()) >= 0)
			{
				return true;//kick this player
			}
		}
		return false;
	}

	public void setServer(int server)
	{
		this.server = server;
	}

	public int getServer()
	{
		return server;
	}

}
